feat(config): add service resource detector support for declarative config#5003
feat(config): add service resource detector support for declarative config#5003MikeGoldsmith wants to merge 18 commits intoopen-telemetry:mainfrom
Conversation
Implements create_resource() and create_propagator()/configure_propagator() for the declarative file configuration. Resource creation does not read OTEL_RESOURCE_ATTRIBUTES or run any detectors (matches Java/JS SDK behavior). Propagator configuration always calls set_global_textmap to override Python's default tracecontext+baggage, setting a noop CompositePropagator when no propagator is configured. Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
- _resource.py: refactor _coerce_attribute_value to dispatch table to avoid too-many-return-statements; fix short variable names k/v -> attr_key/attr_val; fix return type of _sdk_default_attributes to dict[str, str] to satisfy pyright - _propagator.py: rename short variable names e -> exc, p -> propagator - test_resource.py: move imports to top level; split TestCreateResource (25 methods) into three focused classes to satisfy too-many-public-methods - test_propagator.py: add pylint disable for protected-access Assisted-by: Claude Sonnet 4.6
- replace _sdk_default_attributes() with _DEFAULT_RESOURCE from resources module - move _coerce_bool into dispatch tables for both scalar and array bool types, fixing a bug where bool_array with string values like "false" would coerce incorrectly via plain bool() (non-empty string -> True) - add test for bool_array with string values to cover the bug Assisted-by: Claude Sonnet 4.6
… into mike/config-resource-propagator
…erge - collapse _SCALAR_COERCIONS and _ARRAY_COERCIONS into a single _COERCIONS dict using an _array() factory, reducing _coerce_attribute_value to two lines - process attributes_list before attributes so explicit attributes naturally overwrite list entries without needing an explicit guard Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
Adds _run_detectors() stub and _filter_attributes() to create_resource(), providing the shared scaffolding for detector PRs to build on. Detectors are opt-in: nothing runs unless explicitly listed under detection_development.detectors in the config. The include/exclude attribute filter mirrors other SDK behaviour. Assisted-by: Claude Sonnet 4.6
Merges service.name=unknown_service into base before running detectors, so detectors (e.g. service) can override it. Previously it was added to config_attrs and merged last, which would have silently overridden any detector-provided service.name. Assisted-by: Claude Sonnet 4.6
b62c43c to
a2b7031
Compare
Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
Adds service detector support to _run_detectors(): sets a random UUID for service.instance.id and reads OTEL_SERVICE_NAME for service.name if set. Explicit config attributes still take priority (merged last). Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
6fd726b to
2306b93
Compare
…Detector Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
| """ | ||
| if detector_config.service is not None: | ||
| attrs: dict[str, object] = { | ||
| SERVICE_INSTANCE_ID: str(uuid.uuid4()), |
There was a problem hiding this comment.
- Sets
service.instance.idto a random UUID on every process start
I can't remember if this is in the spec already. Feel free to resolve if it is or doesn't need more discussion
There was a problem hiding this comment.
Yes, this is in the spec. The semantic conventions for service.instance.id specify it should be a unique identifier for each instance, with a UUID being the recommended value. The opentelemetry-configuration schema also describes the service detector as populating service.instance.id.
| attrs: dict[str, object] = { | ||
| SERVICE_INSTANCE_ID: str(uuid.uuid4()), | ||
| } | ||
| service_name = os.environ.get(OTEL_SERVICE_NAME) |
There was a problem hiding this comment.
How does this work along with the OTELResourceDetector?
There was a problem hiding this comment.
create_resource intentionally does not invoke OTELResourceDetector and does not read OTEL_RESOURCE_ATTRIBUTES — Declarative config's WYSIWYG semantics mean env vars don't bleed in unless explicitly configured. The one env var the service detector does read is OTEL_SERVICE_NAME, which is intentional per the opentelemetry-configuration schema ("populates service.name based on the OTEL_SERVICE_NAME environment variable"). Java's implementation does the same. JS diverges by only setting service.instance.id and leaving OTEL_SERVICE_NAME to a separate env detector, which may be a bug there (I'm also helping out there so can fix it there too).
Assisted-by: Claude Sonnet 4.6
Description
Implements
serviceresource detector support increate_resource()for the declarative configuration pipeline, as part of the ongoing work tracked in the following PRs:What's included
detection_development.detectors[].servicevia_run_detectors():service.instance.idto a random UUID on every process startOTEL_SERVICE_NAMEenv var forservice.nameif set (mirrors other SDK behaviour)attributesalways take priority over detector-provided valuesservice.name=unknown_servicedefault is set at the lowest priority so any detector or explicit attribute can override itType of change
How Has This Been Tested?
tests/_configuration/test_resource.pydetection_developmentordetectorsis absentDoes This PR Require a Contrib Repo Change?
Checklist:
Assisted-by: Claude Sonnet 4.6